%include 'boot.inc'

section .text

global put_char
global put_str
global put_int
global set_cursor
global clear_screen

put_char:
	push ebx
	push edi
	push esi
	push ebp
	mov ebp,esp
	sub esp,0x10

	mov ax,K_VIDEO_SEL
	mov gs,ax
	
	;read cursor location HI
	mov dx,CRT_ADDR
	mov al,CRT_CUR_LO_HI
	out dx,al
	
	mov dx,CRT_DATA
	in al,dx
	mov ah,al

	;read cursor locaiton low
	mov dx,CRT_ADDR
	mov al,CRT_CUR_LO_LOW
	out dx,al
	
	mov dx,CRT_DATA
	in al,dx

	;now bx is current cursor pos
	mov bx,ax
		
	;get the char test it is normal printable char
	mov ecx,[ebp+20]
	cmp cl,0xd
	jz .cr_start
	cmp cl,0xa
	jz .line_feed_start
	cmp cl,0x8
	jz .backspace
	;now write char to VGA memory
	shl bx,1
	mov byte [gs:bx],cl
	mov byte [gs:bx+1],TEXT_BG_BLACK
	shr bx,1	
	inc bx
	jmp .cursor_process
;here we handle backspace
.backspace:
	sub bx,1
	shl bx,1
	mov byte [gs:bx],' '
	mov byte [gs:bx+1],TEXT_BG_BLACK
	shr bx,1
	jmp .set_cursor
;\r \n we made the the cursor to the next line
.cr_start:
.line_feed_start:
	;first we made cursor return current line start pos	
	xor dx,dx
	mov ax,bx
	mov si,TEXT_MODE_LINE_ROW	
	div si
	sub bx,dx
	;now we made cursor to next line
	add bx,TEXT_MODE_LINE_ROW
.cursor_process:
	cmp bx,TEXT_MODE_LINE_ROW*TEXT_MODE_LINE_COL	
	jl .set_cursor
	;the cursor is out of screen we should roll sreen one line up
	;we rool line 1~last to 0~last-1
	
	cld
	push ds
	push es
	mov ax,K_VIDEO_SEL
	mov ds,ax
	mov es,ax	
	mov ecx,(TEXT_MODE_LINE_COL-1)*TEXT_MODE_LINE_ROW*2/4		
	mov esi,TEXT_MODE_LINE_ROW*2
	mov edi,0
	rep movsd
	pop es
	pop ds
	;clear last line
	xor esi,esi
	mov ecx,TEXT_MODE_LINE_ROW
	mov edx,(TEXT_MODE_LINE_COL-1)*TEXT_MODE_LINE_ROW
	shl edx,1
.cls:
	mov byte [gs:edx+esi],' '
	mov byte [gs:edx+esi+1],TEXT_BG_BLACK
	add esi,2
	loop .cls
	;set cursor to last line start pos
	mov bx,(TEXT_MODE_LINE_COL-1)*TEXT_MODE_LINE_ROW
.set_cursor:
	mov [esp],ebx	
	call set_cursor
	leave
	pop esi
	pop edi
	pop ebx
	ret

section .text
set_cursor:
	push ebp
	mov ebp,esp
	push ebx
	movzx ebx,word [ebp+8]
	mov dx,CRT_ADDR
	mov al,CRT_CUR_LO_HI
	out dx,al	
	
	mov dx,CRT_DATA
	mov al,bh
	out dx,al	
	
	mov dx,CRT_ADDR
	mov al,CRT_CUR_LO_LOW
	out dx,al
	
	mov dx,CRT_DATA
	mov al,bl
	out dx,al
	pop ebx
	leave
	ret
section .text
put_str:
	push ebp
	mov ebp,esp
	sub esp,0x20
	xor esi,esi
	mov ebx,[ebp+8]
.1:
	movzx eax,byte [ebx+esi]	
	cmp eax,0
	jz .end
	inc esi
	mov [esp],eax
	call put_char
	jmp .1
.end:		
	leave
	ret
;put uint32 on screen
section .text
put_int:
	push ebp
	mov ebp,esp
	sub esp,0x28
	mov dword [esp],'0'
	call put_char
	mov dword [esp],'x'
	call put_char
	mov  byte [ebp-0xa],0; flag
	movzx  eax,byte [ebp-0xa]
	mov [ebp-9],al
	jmp .loop_for
.next_n:
	movzx eax,byte [ebp-9]
	mov edx,7
	sub edx,eax
	mov eax,edx
	shl eax,2
	mov [ebp-0xb],al
	movzx eax,byte [ebp-0xb]
	mov edx,[ebp+8]
	mov ecx,eax
	shr edx,cl
	mov eax,edx
	and eax,0x0f
	mov byte [ebp-0xc],al
	cmp byte [ebp-0xc],0
	je .test_flag
	mov byte [ebp-0xa],1
	cmp byte [ebp-0xc],9
	ja .print_aa
	movzx eax,byte [ebp-0xc]
	add eax,'0'
	mov [esp],eax
	call put_char
	jmp  .test_i
.print_aa:
	movzx eax,byte [ebp-0xc]
	add eax,0x57
	mov [esp],eax
	call put_char
	jmp .test_i
.test_flag:
	;when flag set zero should print
	cmp byte [ebp-0xa],0
	je .test_i
	mov dword [esp],'0'
	call put_char
.test_i:
	movzx eax,byte [ebp-9]
	add eax,1
	mov [ebp-9],al
.loop_for:
	cmp byte [ebp-9],7
	jbe .next_n
	cmp byte [ebp-9],8
	jne .ret
	cmp byte [ebp-0xa],0
	jne .ret
	mov dword [esp],'0'
	call put_char
.ret:
	leave
	ret

section .text
clear_screen:
	push ebp
	mov ebp,esp
	sub esp,4
	mov ax,K_VIDEO_SEL
	mov gs,ax
	mov ecx,TEXT_MODE_LINE_COL*TEXT_MODE_LINE_ROW
	mov edx,0
.cls:
	mov byte [gs:edx],' '
	mov byte [gs:edx+1],TEXT_BG_BLACK
	add edx,2	
	loop .cls
	mov dword [esp],0
	call set_cursor
	leave
	ret
